 /*******************************************************************************
  * Copyright (c) 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal.texteditor;

 import java.util.HashMap ;
 import java.util.Iterator ;
 import java.util.LinkedHashSet ;
 import java.util.Map ;
 import java.util.Set ;

 import org.eclipse.core.runtime.Assert;

 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.PropertyChangeEvent;

 public final class PropertyEventDispatcher {
     private final Map fHandlerMap= new HashMap ();
     private final Map fReverseMap= new HashMap ();
     private final IPreferenceStore fStore;
     private final IPropertyChangeListener fListener= new IPropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent event) {
             firePropertyChange(event);
         }
     };
     public PropertyEventDispatcher(IPreferenceStore store) {
         Assert.isLegal(store != null);
         fStore= store;
     }
     public void dispose() {
         if (!fReverseMap.isEmpty())
             fStore.removePropertyChangeListener(fListener);
         fReverseMap.clear();
         fHandlerMap.clear();
     }
     private void firePropertyChange(PropertyChangeEvent event) {
         Object value= fHandlerMap.get(event.getProperty());
         if (value instanceof IPropertyChangeListener)
             ((IPropertyChangeListener) value).propertyChange(event);
         else if (value instanceof Set )
             for (Iterator it= ((Set ) value).iterator(); it.hasNext(); )
                 ((IPropertyChangeListener) it.next()).propertyChange(event);
     }
     public void addPropertyChangeListener(String property, IPropertyChangeListener listener) {
         Assert.isLegal(property != null);
         Assert.isLegal(listener != null);

         if (fReverseMap.isEmpty())
             fStore.addPropertyChangeListener(fListener);

         multiMapPut(fHandlerMap, property, listener);
         multiMapPut(fReverseMap, listener, property);
     }
     private void multiMapPut(Map map, Object key, Object value) {
         Object mapping= map.get(key);
         if (mapping == null) {
             map.put(key, value);
         } else if (mapping instanceof Set ) {
             ((Set ) mapping).add(value);
         } else {
             Set set= new LinkedHashSet ();
             set.add(mapping);
             set.add(value);
             map.put(key, set);
         }
     }
     private void multiMapRemove(Map map, Object key, Object value) {
         Object mapping= map.get(key);
         if (mapping instanceof Set ) {
             ((Set ) mapping).remove(value);
         } else if (mapping != null) {
             map.remove(key);
         }
     }
     public void removePropertyChangeListener(IPropertyChangeListener listener) {
         Object value= fReverseMap.get(listener);
         if (value == null)
             return;
         if (value instanceof String ) {
             fReverseMap.remove(listener);
             multiMapRemove(fHandlerMap, value, listener);
         } else if (value instanceof Set ) {
             fReverseMap.remove(listener);
             for (Iterator it= ((Set ) value).iterator(); it.hasNext();)
                 multiMapRemove(fHandlerMap, it.next(), listener);
         }

         if (fReverseMap.isEmpty())
             fStore.removePropertyChangeListener(fListener);
     }
 }
